//
//  InteractivePop.m
//  FFStory
//
//  Created by BaeCheung on 14/11/12.
//  Copyright (c) 2014年 FF. All rights reserved.
//

#import "InteractivePop.h"
#import "InteractivePopAnimator.h"

@interface InteractivePop() <UIGestureRecognizerDelegate>
@property (weak, nonatomic) FFNavigationController *navigationController;
@property (strong, nonatomic) InteractivePopAnimator *animator;
@property (strong, nonatomic) UIPanGestureRecognizer *recognizer;
@property (strong, nonatomic) UIPercentDrivenInteractiveTransition *interactionController;
/// A Boolean value that indicates whether the navigation controller is currently animating a push/pop operation.
@property (nonatomic) BOOL duringAnimation;
@end

@implementation InteractivePop

- (instancetype)initWithNavigationController:(FFNavigationController *)navigationController {
    if (self = [super init]) {
        _navigationController = navigationController;
        // Animator
        _animator = [[InteractivePopAnimator alloc] init];
        // Recognizer
        _recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
        _recognizer.maximumNumberOfTouches = 1;
        _recognizer.delegate = self;
        [navigationController.view addGestureRecognizer:_recognizer];
    }
    return self;
}

#pragma mark - UIPanGestureRecognizer

// 确保只有在子一级手势才会响应
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    return _interactivePopEnable && self.navigationController.viewControllers.count > 1 && !self.duringAnimation;
}

// 只支持右滑返回
- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer {
    CGPoint velocity = [gestureRecognizer velocityInView:self.navigationController.view];
    return velocity.x > 0 && velocity.x > fabs(velocity.y);
}

// UIScrollView 滑动到最左侧时也允许返回
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    if ([otherGestureRecognizer isKindOfClass:NSClassFromString(@"UIScrollViewPanGestureRecognizer")]) {
        UIScrollView *scrollView = (UIScrollView *)otherGestureRecognizer.view;
        if ([_navigationController shouldSimultaneouslyScrollView:scrollView]) {
            if (scrollView.contentOffset.x == 0) {
                CGPoint velocity = [scrollView.panGestureRecognizer velocityInView:scrollView];
                if (velocity.x > 0) {
                    return YES;
                }
            }
        }
    }
    return NO;
}

- (void)pan:(UIPanGestureRecognizer *)recognizer
{
    UIView *view = self.navigationController.view;
    if (recognizer.state == UIGestureRecognizerStateBegan) {
        if (self.navigationController.viewControllers.count > 1 && !self.duringAnimation) {
            self.interactionController = [[UIPercentDrivenInteractiveTransition alloc] init];
            self.interactionController.completionCurve = UIViewAnimationCurveEaseOut;
            // 手势开始
            self.duringAnimation = YES;
            [self.navigationController popViewControllerAnimated:YES];
        }
    } else if (recognizer.state == UIGestureRecognizerStateChanged) {
        // Update
        CGPoint translation = [recognizer translationInView:view];
        CGFloat d = translation.x / CGRectGetWidth(view.bounds);
        [self.interactionController updateInteractiveTransition:MAX(d, 0)];
    } else if (recognizer.state == UIGestureRecognizerStateEnded) {
        // Swipe right
        BOOL finishInteractive = [recognizer velocityInView:view].x > 0;
        if (finishInteractive) {
            // At least 25% move
            CGPoint translation = [recognizer translationInView:view];
            finishInteractive = translation.x / CGRectGetWidth(view.bounds) > 0.2;
        }
        if (finishInteractive) {
            [self.interactionController finishInteractiveTransition];
        } else {
            [self.interactionController cancelInteractiveTransition];
            // When the transition is cancelled, `navigationController:didShowViewController:animated:` isn't called, so we have to maintain `duringAnimation`'s state here too.
            self.duringAnimation = NO;
        }
        self.interactionController = nil;
    }
}

#pragma mark - UINavigationControllerDelegate

- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC {
    BOOL animator = self.duringAnimation && operation == UINavigationControllerOperationPop;
    return animator ? self.animator : nil;
}

- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController {
    return self.interactionController;
}

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    self.duringAnimation = NO;
}

@end
